#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""可视化UI设计器组件"""

from PyQt5.QtWidgets import (
    QWidget, QVBoxLayout, QHBoxLayout, QScrollArea, QToolBox,
    QPushButton, QLabel, QLineEdit, QTextEdit, QCheckBox,
    QRadioButton, QComboBox, QSpinBox, QDoubleSpinBox, QGroupBox,
    QFrame, QSplitter, QApplication, QMessageBox
)
from PyQt5.QtCore import Qt, QPoint, QEvent, QSize, QMimeData
from PyQt5.QtGui import QDrag, QPainter, QPen, QColor, QFont, QPixmap


class ComponentPalette(QToolBox):
    """组件面板，包含所有可用的UI组件"""
    
    def __init__(self, parent=None):
        """初始化组件面板"""
        super().__init__(parent)
        
        self.setWindowTitle("组件面板")
        self.setMinimumWidth(120)
        
        # 创建基本组件页
        self.basic_widget = QWidget()
        basic_layout = QVBoxLayout(self.basic_widget)
        basic_layout.setContentsMargins(5, 5, 5, 5)
        
        # 添加基本组件
        components = [
            ("按钮", QPushButton),
            ("标签", QLabel),
            ("文本框", QLineEdit),
            ("多行文本框", QTextEdit),
            ("复选框", QCheckBox),
            ("单选按钮", QRadioButton),
            ("下拉框", QComboBox),
            ("整数输入框", QSpinBox),
            ("浮点数输入框", QDoubleSpinBox),
            ("分组框", QGroupBox),
            ("框架", QFrame)
        ]
        
        for name, component_class in components:
            tool_button = QPushButton(name)
            tool_button.setFixedSize(100, 30)
            tool_button.setToolTip(name)
            tool_button.setProperty("component_class", component_class)
            tool_button.setProperty("component_name", name)
            tool_button.clicked.connect(self.on_tool_button_clicked)
            tool_button.mousePressEvent = self.on_mouse_press_event
            basic_layout.addWidget(tool_button)
        
        basic_layout.addStretch()
        
        # 添加到工具箱
        self.addItem(self.basic_widget, "基本组件")
        
    def on_tool_button_clicked(self):
        """工具按钮点击事件"""
        button = self.sender()
        component_class = button.property("component_class")
        component_name = button.property("component_name")
        
        # 这里可以添加组件创建逻辑
        print(f"创建组件: {component_name}")
    
    def on_mouse_press_event(self, event):
        """鼠标按下事件，用于启动拖放操作"""
        if event.button() == Qt.LeftButton:
            # 当方法直接赋值给按钮时，self.sender()不可靠
            # 我们需要找到触发事件的按钮
            button = self.sender()
            if button is None:
                # 如果sender()返回None，则检查哪个按钮触发了事件
                # 在这种情况下，self就是按钮本身
                if hasattr(self, 'property'):
                    button = self
                else:
                    return
            
            component_class = button.property("component_class")
            component_name = button.property("component_name")
            
            # 创建拖放对象
            drag = QDrag(button)
            mime_data = QMimeData()
            mime_data.setText(f"component:{component_name}:{component_class.__name__}")
            drag.setMimeData(mime_data)
            
            # 设置拖动时的图标
            pixmap = QPixmap(32, 32)
            pixmap.fill(Qt.white)
            painter = QPainter(pixmap)
            painter.drawText(0, 20, component_name[:2])
            painter.end()
            drag.setPixmap(pixmap)
            
            # 开始拖放
            drag.exec_(Qt.CopyAction)
            
            # 调用原有的鼠标按下事件处理
            super(QPushButton, button).mousePressEvent(event) if hasattr(button, 'mousePressEvent') else None


class DesignCanvas(QWidget):
    """设计画布，用于拖放和布局组件"""
    
    def __init__(self, parent=None):
        """初始化设计画布"""
        super().__init__(parent)
        
        # 设置画布属性
        self.setMinimumSize(800, 600)
        self.setStyleSheet("background-color: #f0f0f0;")
        
        # 存储组件信息
        self.components = []
        self.selected_component = None
        
        # 网格设置
        self.show_grid = True
        self.grid_size = 10
        
        # 辅助线设置
        self.show_guides = False
        self.guides = []
        
        # 启用鼠标跟踪
        self.setMouseTracking(True)
        
        # 启用拖放
        self.setAcceptDrops(True)
        
        # 拖动相关变量
        self.dragging_component = None
        self.drag_start_position = QPoint()
        self.is_moving = False
    
    def paintEvent(self, event):
        """绘制事件"""
        super().paintEvent(event)
        
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        
        # 绘制网格
        if self.show_grid:
            self.draw_grid(painter)
        
        # 绘制辅助线
        if self.show_guides:
            self.draw_guides(painter)
        
        # 绘制选中组件的边框
        if self.selected_component:
            self.draw_selected_frame(painter)
    
    def draw_grid(self, painter):
        """绘制网格"""
        pen = QPen(QColor(200, 200, 200), 1, Qt.DotLine)
        painter.setPen(pen)
        
        # 绘制垂直线
        for x in range(0, self.width(), self.grid_size):
            painter.drawLine(x, 0, x, self.height())
        
        # 绘制水平线
        for y in range(0, self.height(), self.grid_size):
            painter.drawLine(0, y, self.width(), y)
    
    def draw_guides(self, painter):
        """绘制辅助线"""
        pen = QPen(QColor(255, 0, 0), 1, Qt.DashLine)
        painter.setPen(pen)
        
        for guide in self.guides:
            if guide['orientation'] == 'vertical':
                painter.drawLine(guide['position'], 0, guide['position'], self.height())
            else:
                painter.drawLine(0, guide['position'], self.width(), guide['position'])
    
    def draw_selected_frame(self, painter):
        """绘制选中组件的边框"""
        if not self.selected_component:
            return
        
        # 获取组件位置和大小
        rect = self.selected_component.geometry()
        
        # 绘制边框
        pen = QPen(QColor(0, 120, 215), 2, Qt.SolidLine)
        painter.setPen(pen)
        painter.drawRect(rect.x() - 1, rect.y() - 1, rect.width() + 1, rect.height() + 1)
        
        # 绘制调整大小的控制点
        pen.setWidth(3)
        painter.setPen(pen)
        painter.drawPoint(rect.x() - 1, rect.y() - 1)  # 左上
        painter.drawPoint(rect.right(), rect.y() - 1)  # 右上
        painter.drawPoint(rect.x() - 1, rect.bottom())  # 左下
        painter.drawPoint(rect.right(), rect.bottom())  # 右下
    
    def mousePressEvent(self, event):
        """鼠标按下事件"""
        if event.button() == Qt.LeftButton:
            # 检查是否点击了某个组件
            clicked_component = None
            for component in reversed(self.components):
                if component.geometry().contains(event.pos()):
                    clicked_component = component
                    break
            
            if clicked_component:
                # 选中组件
                self.selected_component = clicked_component
                self.dragging_component = clicked_component
                self.drag_start_position = event.pos()
                self.is_moving = False
                self.update()
                
                # 发送组件选中信号
                if hasattr(self.parent(), 'on_component_selected'):
                    self.parent().on_component_selected(clicked_component)
            else:
                # 取消选中
                self.selected_component = None
                self.dragging_component = None
                self.update()
    
    def mouseMoveEvent(self, event):
        """鼠标移动事件"""
        # 如果有选中的组件并且鼠标移动距离超过阈值，则开始移动组件
        if self.dragging_component and event.buttons() == Qt.LeftButton:
            distance = (event.pos() - self.drag_start_position).manhattanLength()
            if distance > QApplication.startDragDistance():
                self.is_moving = True
                # 对齐到网格
                x = event.pos().x() - self.drag_start_position.x()
                y = event.pos().y() - self.drag_start_position.y()
                
                new_pos = self.dragging_component.pos() + QPoint(x, y)
                
                # 网格对齐
                new_pos.setX(new_pos.x() - (new_pos.x() % self.grid_size))
                new_pos.setY(new_pos.y() - (new_pos.y() % self.grid_size))
                
                self.dragging_component.move(new_pos)
                self.update()
    
    def mouseReleaseEvent(self, event):
        """鼠标释放事件"""
        if self.dragging_component and event.button() == Qt.LeftButton:
            self.dragging_component = None
            self.is_moving = False
    
    def dragEnterEvent(self, event):
        """处理拖动进入事件"""
        if event.mimeData().hasText() and event.mimeData().text().startswith("component:"):
            event.acceptProposedAction()
    
    def dragMoveEvent(self, event):
        """处理拖动移动事件"""
        if event.mimeData().hasText() and event.mimeData().text().startswith("component:"):
            event.acceptProposedAction()
    
    def dropEvent(self, event):
        """处理放置事件"""
        if event.mimeData().hasText() and event.mimeData().text().startswith("component:"):
            # 解析MIME数据
            mime_text = event.mimeData().text()
            parts = mime_text.split(":")
            if len(parts) >= 3:
                component_name = parts[1]
                component_class_name = parts[2]
                
                # 根据类名找到对应的组件类
                component_class = None
                for name, cls in [
                    ("按钮", QPushButton),
                    ("标签", QLabel),
                    ("文本框", QLineEdit),
                    ("多行文本框", QTextEdit),
                    ("复选框", QCheckBox),
                    ("单选按钮", QRadioButton),
                    ("下拉框", QComboBox),
                    ("整数输入框", QSpinBox),
                    ("浮点数输入框", QDoubleSpinBox),
                    ("分组框", QGroupBox),
                    ("框架", QFrame)
                ]:
                    if cls.__name__ == component_class_name:
                        component_class = cls
                        break
                
                if component_class:
                    # 获取放置位置
                    drop_pos = self.mapFromGlobal(event.pos())
                    
                    # 添加组件到画布
                    self.add_component(component_class, drop_pos)
                
            event.acceptProposedAction()
    
    def add_component(self, component_class, pos=None):
        """添加组件到画布"""
        component = component_class(self)
        
        # 设置组件基本属性
        component.setObjectName(f"{component_class.__name__}{len(self.components) + 1}")
        component.setGeometry(50, 50, 100, 30)
        
        # 如果指定了位置，则设置位置
        if pos:
            # 对齐到网格
            x = pos.x() - (pos.x() % self.grid_size)
            y = pos.y() - (pos.y() % self.grid_size)
            component.move(x, y)
        
        # 显示组件
        component.show()
        
        # 添加到组件列表
        self.components.append(component)
        
        # 选中新添加的组件
        self.selected_component = component
        self.update()
        
        # 发送组件选中信号
        if hasattr(self.parent(), 'on_component_selected'):
            self.parent().on_component_selected(component)
        
        return component
    
    def remove_component(self, component):
        """从画布中移除组件"""
        if component in self.components:
            self.components.remove(component)
            component.deleteLater()
            
            if self.selected_component == component:
                self.selected_component = None
            
            self.update()
    
    def clear(self):
        """清空画布"""
        for component in self.components[:]:
            self.remove_component(component)
    
    def set_component_property(self, component, property_name, value):
        """设置组件属性"""
        if hasattr(component, property_name):
            setattr(component, property_name, value)
            self.update()
            return True
        return False
    
    def get_component_properties(self, component):
        """获取组件的可编辑属性"""
        properties = {}
        
        # 基本属性
        properties['objectName'] = component.objectName()
        properties['geometry'] = component.geometry()
        properties['minimumSize'] = component.minimumSize()
        properties['maximumSize'] = component.maximumSize()
        properties['enabled'] = component.isEnabled()
        
        # 根据组件类型添加特定属性
        if isinstance(component, QPushButton):
            properties['text'] = component.text()
            properties['checkable'] = component.isCheckable()
            properties['checked'] = component.isChecked()
        elif isinstance(component, QLabel):
            properties['text'] = component.text()
            properties['alignment'] = component.alignment()
        elif isinstance(component, QLineEdit):
            properties['text'] = component.text()
            properties['placeholderText'] = component.placeholderText()
            properties['readOnly'] = component.isReadOnly()
        elif isinstance(component, QTextEdit):
            properties['plainText'] = component.toPlainText()
            properties['readOnly'] = component.isReadOnly()
        
        return properties


class UIDesigner(QWidget):
    """可视化UI设计器"""
    
    def __init__(self, parent=None):
        """初始化UI设计器"""
        super().__init__(parent)
        
        # 创建主布局
        main_layout = QHBoxLayout(self)
        
        # 创建组件面板
        self.component_palette = ComponentPalette()
        main_layout.addWidget(self.component_palette)
        
        # 创建设计画布
        self.canvas_widget = QWidget()
        canvas_layout = QVBoxLayout(self.canvas_widget)
        
        # 创建滚动区域，包裹设计画布
        scroll_area = QScrollArea()
        scroll_area.setWidgetResizable(True)
        
        self.canvas = DesignCanvas(self)
        self.canvas.setObjectName("DesignCanvas")
        scroll_area.setWidget(self.canvas)
        
        canvas_layout.addWidget(scroll_area)
        
        main_layout.addWidget(self.canvas_widget, 1)
        
        # 连接信号和槽
        self.setup_connections()
    
    def setup_connections(self):
        """设置信号和槽的连接"""
        # 这里可以添加信号和槽的连接
        pass
    
    def on_component_selected(self, component):
        """组件选中事件处理"""
        print(f"选中组件: {component.objectName()}")
        
        # 这里可以发送信号给属性编辑器
        if hasattr(self.parent(), 'property_editor'):
            properties = self.canvas.get_component_properties(component)
            self.parent().property_editor.set_component(component, properties)
    
    def add_component_to_canvas(self, component_class, pos=None):
        """向画布添加组件"""
        return self.canvas.add_component(component_class, pos)
    
    def generate_code(self):
        """生成当前UI的Python代码"""
        code = '''#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""由Python Delphi-like IDE自动生成的UI代码"""

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *


class GeneratedUI(QWidget):
    """自动生成的UI类"""
    
    def __init__(self, parent=None):
        """初始化UI"""
        super().__init__(parent)
        
        # 设置窗口属性
        self.setWindowTitle("Generated UI")
        
        # 创建布局
        self.layout = QVBoxLayout(self)
        
        # 添加组件
'''
        
        # 添加生成的组件代码
        for component in self.canvas.components:
            component_code = self.generate_component_code(component)
            code += component_code
        
        code += '''

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ui = GeneratedUI()
    ui.show()
    sys.exit(app.exec_())
'''
        
        return code
    
    def generate_component_code(self, component):
        """生成单个组件的代码"""
        component_name = component.objectName()
        component_class = component.__class__.__name__
        
        # 基本创建代码
        code = f"        self.{component_name} = {component_class}()\n"
        code += f"        self.{component_name}.setObjectName('{component_name}')\n"
        
        # 添加几何属性
        geometry = component.geometry()
        code += f"        self.{component_name}.setGeometry({geometry.x()}, {geometry.y()}, {geometry.width()}, {geometry.height()})\n"
        
        # 根据组件类型添加特定属性
        if isinstance(component, QPushButton):
            text = component.text()
            code += f"        self.{component_name}.setText('{text}')\n"
        elif isinstance(component, QLabel):
            text = component.text()
            code += f"        self.{component_name}.setText('{text}')\n"
        
        # 添加到布局
        code += f"        self.layout.addWidget(self.{component_name})\n\n"
        
        return code